package cn.iocoder.yudao.module.engine.service.core.queue.audio.impl;

import cn.iocoder.yudao.module.engine.enums.EnumAudioType;
import cn.iocoder.yudao.module.engine.model.engine.EngineOutputData;
import cn.iocoder.yudao.module.engine.service.core.queue.audio.AudioQueue;
import cn.iocoder.yudao.module.resource.api.enums.MessageSourceTypeEnum;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class PriorityLimitedAudioQueue implements AudioQueue {
    private final LinkedList<EngineOutputData.Audio> queue;
    private final ReentrantLock lock;

    public PriorityLimitedAudioQueue() {
        queue = new LinkedList<>();
        lock = new ReentrantLock();
    }

    public boolean addAudio(EngineOutputData.Audio audio) {
        lock.lock();
        try {
            final EnumAudioType newAudioType = audio.getAudioType();
            final int newPriority = newAudioType.getPriority();

            // 检查队列中是否有比新消息优先级更高的消息
            final boolean hasHigherPriority = queue.stream()
                    .anyMatch(msg -> msg.getAudioType().getPriority() < newPriority);
            if (hasHigherPriority) {
                log.info("队列中存在优先级更高的消息，不添加新消息，newAudioType={}，newPriority={}",
                        newAudioType, newPriority);
                return false;
            }

            // 移除队列中优先级比新消息低的消息
            final boolean removedLessPriority = queue.removeIf(msg ->
                    msg.getAudioType().getPriority() > newPriority);
            if (removedLessPriority) {
                log.info("移除了优先级比新消息低的消息，newAudioType={}，newPriority={}",
                        newAudioType, newPriority);
            }

            String newChatId = audio.getChatId();
            boolean chatIdExists = false;
            int insertIndex = 0;

            // 检查 chatId 是否已存在于队列中
            for (int i = queue.size() - 1; i >= 0; i--) {
                EngineOutputData.Audio currentMessage = queue.get(i);
                if (currentMessage.getChatId().equals(newChatId)) {
                    chatIdExists = true;
                    insertIndex = i + 1;
                    break;
                }
            }

            if (chatIdExists) {
                // 如果 chatId 已存在，插入到相同 chatId 的下面
                queue.add(insertIndex, audio);
                log.info("chatId已存在，插入到相同chatId的下面, newChatId = {}", newChatId);
                return true;
            } else {
                int differentChatIds = getDifferentChatIdCount();
                if (differentChatIds < 2) {
                    // 如果不同的 chatId 数量不超过 2 个，直接添加消息
                    queue.add(audio);
                    log.info("不同的chatId数量不超过2个，直接添加消息, newChatId = {}", newChatId);
                    return true;
                } else {
                    // 如果不同的 chatId 数量超过 2 个，清空最新的 chatId 相关的消息
                    final String latestChatId = queue.getLast().getChatId();
                    final boolean removed = queue.removeIf(msg -> msg.getChatId().equals(latestChatId));
                    if (removed) {
                        log.info("chatId超过2个，移除了最新的chatId相关的消息, latestChatId = {}", latestChatId);
                    }
                    // 添加新消息
                    queue.add(audio);
                    log.info("chatId超过2个，添加新消息, newChatId = {}", newChatId);
                    return true;
                }
            }
        } finally {
            lock.unlock();
        }
    }

    public EngineOutputData.Audio removeAudio() {
        lock.lock();
        try {
            if (queue.isEmpty()) {
                return null;
            }
            return queue.removeFirst();
        } finally {
            lock.unlock();
        }
    }

    public void clear() {
        lock.lock();
        try {
            queue.clear();
        } finally {
            lock.unlock();
        }
    }

    private int getDifferentChatIdCount() {
        int count = 0;
        String firstChatId = null;
        String secondChatId = null;
        for (EngineOutputData.Audio message : queue) {
            String chatId = message.getChatId();
            if (firstChatId == null) {
                firstChatId = chatId;
                count++;
            } else if (!chatId.equals(firstChatId) && (secondChatId == null || !chatId.equals(secondChatId))) {
                if (secondChatId == null) {
                    secondChatId = chatId;
                    count++;
                }
            }
        }
        return count;
    }

    public List<EngineOutputData.Audio> getDataList() {
        lock.lock();
        try {
            return new ArrayList<>(queue);
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
//        PriorityLimitedAudioQueue audioQueue = new PriorityLimitedAudioQueue();
//
//        audioQueue.addAudio(new EngineOutputData.Audio("bgm-a", MessageSourceTypeEnum.AI, "bgm-a1", EnumAudioType.BGM, null, null, 1, null, null, null, null, null, null));
//        System.out.println(audioQueue.getDataList().stream().map(v -> v.getAudioId()).toList());
//
//        audioQueue.addAudio(new EngineOutputData.Audio("a", MessageSourceTypeEnum.AI, "a1", EnumAudioType.MAIN, null, null, 1, null, null, null, null, null, null));
//        System.out.println(audioQueue.getDataList().stream().map(v -> v.getAudioId()).toList());
//
//        audioQueue.addAudio(new EngineOutputData.Audio("b", MessageSourceTypeEnum.AI, "b1", EnumAudioType.MAIN, null, null, 1, null, null, null, null, null, null));
//        System.out.println(audioQueue.getDataList().stream().map(v -> v.getAudioId()).toList());
//
//        audioQueue.addAudio(new EngineOutputData.Audio("a", MessageSourceTypeEnum.AI, "a2", EnumAudioType.MAIN, null, null, 1, null, null, null, null, null, null));
//        System.out.println(audioQueue.getDataList().stream().map(v -> v.getAudioId()).toList());
//
//        audioQueue.addAudio(new EngineOutputData.Audio("b", MessageSourceTypeEnum.AI, "b2", EnumAudioType.MAIN, null, null, 1, null, null, null, null, null, null));
//        System.out.println(audioQueue.getDataList().stream().map(v -> v.getAudioId()).toList());
//
//        audioQueue.addAudio(new EngineOutputData.Audio("c", MessageSourceTypeEnum.AI, "c1", EnumAudioType.MAIN, null, null, 1, null, null, null, null, null, null));
//        System.out.println(audioQueue.getDataList().stream().map(v -> v.getAudioId()).toList());
//
//        audioQueue.addAudio(new EngineOutputData.Audio("c", MessageSourceTypeEnum.AI, "c2", EnumAudioType.MAIN, null, null, 1, null, null, null, null, null, null));
//        System.out.println(audioQueue.getDataList().stream().map(v -> v.getAudioId()).toList());
//
//        audioQueue.removeAudio();
//        System.out.println(audioQueue.getDataList().stream().map(v -> v.getAudioId()).toList());
//
//        audioQueue.addAudio(new EngineOutputData.Audio("bgm-a", MessageSourceTypeEnum.AI, "bgm-a2", EnumAudioType.BGM, null, null, 1, null, null, null, null, null, null));
//        System.out.println(audioQueue.getDataList().stream().map(v -> v.getAudioId()).toList());
    }

}
